nanopyx.methods.drift_alignment.estimator
1import numpy as np 2from math import sqrt 3from scipy.interpolate import interp1d 4 5from .estimator_table import DriftEstimatorTable 6from .corrector import DriftCorrector 7from ...core.analysis.estimate_shift import GetMaxOptimizer 8from ...core.utils.timeit import timeit 9from ...core.analysis.ccm import calculate_ccm 10from ...core.analysis.rcc import rcc 11 12 13class DriftEstimator(object): 14 15 def __init__(self): 16 self.estimator_table = DriftEstimatorTable() 17 self.cross_correlation_map = None 18 self.drift_xy = None 19 self.drift_x = None 20 self.drift_y = None 21 22 # @timeit 23 def estimate(self, image_array, **kwargs): 24 self.set_estimator_params(**kwargs) 25 26 n_slices = image_array.shape[0] 27 28 # x0, y0, x1, y1 correspond to the exact coordinates of the roi to be used or full image dims and should be a tuple 29 if self.estimator_table.params["use_roi"] and self.estimator_table.params["roi"] is not None: # crops image to roi 30 print(self.estimator_table.params["use_roi"], self.estimator_table.params["roi"]) 31 x0, y0, x1, y1 = tuple(self.estimator_table.params["roi"]) 32 image_arr = image_array[:, y0:y1+1, x0:x1+1] 33 else: 34 image_arr = image_array 35 36 # checks time averaging, in case it's lower than 1 defaults to 1 37 # if higher than n_slices/2 defaults to n_slices/2 38 if self.estimator_table.params["time_averaging"] < 1: 39 self.estimator_table.params["time_averaging"] = 1 40 elif self.estimator_table.params["time_averaging"] > int(n_slices/2): 41 self.estimator_table.params["time_averaging"] = int(n_slices/2) 42 43 # case of no temporal averaging 44 if self.estimator_table.params["time_averaging"] == 1: 45 image_averages = image_arr 46 else: # case of temporal averaging 47 # calculates number of time blocks for averaging 48 image_averages = self.compute_temporal_averaging(image_arr) 49 50 method = self.estimator_table.params["shift_calc_method"] 51 52 if method == "rcc": 53 shifts = rcc(image_averages, max_shift=self.estimator_table.params["max_expected_drift"]) 54 self.drift_x = shifts[0] 55 self.drift_y = shifts[1] 56 else: 57 self.cross_correlation_map = np.array(calculate_ccm(np.array(image_averages).astype(np.float32), self.estimator_table.params["ref_option"])) 58 max_shift = self.estimator_table.params["max_expected_drift"] 59 if max_shift > 0 and max_shift*2+1 < self.cross_correlation_map.shape[1] and max_shift*2+1 < self.cross_correlation_map.shape[2]: 60 ccm_x_start = int(self.cross_correlation_map.shape[1]/2 - max_shift) 61 ccm_y_start = int(self.cross_correlation_map.shape[0]/2 - max_shift) 62 slice_ccm = self.cross_correlation_map[ccm_y_start:ccm_y_start+(max_shift*2), ccm_x_start:ccm_x_start+(max_shift*2)] 63 self.get_shifts_from_ccm() 64 65 if self.estimator_table.params["time_averaging"] > 1: 66 67 print("Interpolating time points") 68 x_idx = np.linspace(1, image_array.shape[0], num=self.drift_x.shape[0], endpoint=True, dtype=int) 69 x_interpolator = interp1d(x_idx, self.drift_x, kind="cubic") # linear seems to work similar as in nanoj-core however its codebase calls setInterpolation("Bicubic") 70 self.drift_x = x_interpolator(range(1, image_array.shape[0] + 1)) 71 y_idx = np.linspace(1, image_array.shape[0], num=self.drift_y.shape[0], endpoint=True, dtype=int) 72 y_interpolator = interp1d(y_idx, self.drift_y, kind="cubic") # linear seems to work similar as in nanoj-core however its codebase calls setInterpolation("Bicubic") 73 self.drift_y = y_interpolator(range(1, image_array.shape[0] + 1)) 74 75 self.drift_xy = [] 76 for i in range(image_array.shape[0]): 77 self.drift_xy.append(sqrt(pow(self.drift_x[i], 2) + pow(self.drift_y[i], 2))) 78 self.drift_xy = np.array(self.drift_xy) 79 80 self.create_drift_table() 81 82 if self.estimator_table.params["apply"]: 83 drift_corrector = DriftCorrector() 84 drift_corrector.estimator_table = self.estimator_table 85 tmp = drift_corrector.apply_correction(image_array) 86 return tmp 87 else: 88 return None 89 90 def compute_temporal_averaging(self, image_arr): 91 n_slices = image_arr.shape[0] 92 93 if self.estimator_table.params["use_roi"]: 94 x0, y0, x1, y1 = self.estimator_table.params["roi"] 95 else: 96 x0, y0, x1, y1 = 0, 0, image_arr.shape[2]-1, image_arr.shape[1]-1 97 98 n_blocks = int(n_slices / self.estimator_table.params["time_averaging"]) 99 if (n_slices % self.estimator_table.params["time_averaging"]) != 0: 100 n_blocks += 1 101 image_averages = np.zeros((n_blocks, y1+1-y0, x1+1-x0)) 102 for i in range(n_blocks): 103 t_start = i * self.estimator_table.params["time_averaging"] 104 t_stop = (i + 1) * self.estimator_table.params["time_averaging"] 105 image_averages[i] = np.mean(image_arr[t_start:t_stop, :, :], axis=0) 106 return image_averages 107 108 def get_shift_from_ccm_slice(self, slice_index): 109 slice_ccm = self.cross_correlation_map[slice_index] 110 111 w = slice_ccm.shape[1] 112 h = slice_ccm.shape[0] 113 114 radius_x = w / 2.0 115 radius_y = h / 2.0 116 117 method = self.estimator_table.params["shift_calc_method"] 118 119 if method == "Max Fitting": 120 optimizer = GetMaxOptimizer(slice_ccm) 121 shift_y, shift_x = optimizer.get_max() 122 elif method == "Max": 123 shift_y, shift_x = np.unravel_index(slice_ccm.argmax(), slice_ccm.shape) 124 125 shift_x = round(radius_x - shift_x - 0.5, 3) 126 shift_y = round(radius_y - shift_y - 0.5, 3) 127 128 return (shift_x, shift_y) 129 130 def get_shifts_from_ccm(self): 131 132 drift_x = [] 133 drift_y = [] 134 drift = [] 135 136 for i in range(self.cross_correlation_map.shape[0]): 137 drift.append(self.get_shift_from_ccm_slice(i)) 138 139 drift = np.array(drift) 140 drift_x = drift[:, 0] 141 drift_y = drift[:, 1] 142 143 bias_x = drift_x[0] 144 bias_y = drift_y[0] 145 146 self.drift_x = np.zeros((drift_x.shape[0])) 147 self.drift_y = np.zeros((drift_y.shape[0])) 148 149 for i in range(0, self.cross_correlation_map.shape[0]): 150 self.drift_x[i] = drift_x[i] - bias_x 151 self.drift_y[i] = drift_y[i] - bias_y 152 if self.estimator_table.params["ref_option"] == 1 and i > 0: 153 self.drift_x[i] += self.drift_x[i-1] 154 self.drift_y[i] += self.drift_y[i-1] 155 156 self.drift_x = np.array(self.drift_x) 157 self.drift_y = np.array(self.drift_y) 158 159 def create_drift_table(self): 160 table = [] 161 for i in range(0, self.drift_xy.shape[0]): 162 table.append([self.drift_xy[i], self.drift_x[i], self.drift_y[i]]) 163 table = np.array(table) 164 self.estimator_table.drift_table = table 165 166 def save_drift_table(self, save_as_npy=True, path=None): 167 if save_as_npy: 168 self.estimator_table.export_npy(path=path) 169 else: 170 self.estimator_table.export_csv(path=path) 171 172 def set_estimator_params(self, **kwargs): 173 self.estimator_table.set_params(**kwargs)
class
DriftEstimator:
14class DriftEstimator(object): 15 16 def __init__(self): 17 self.estimator_table = DriftEstimatorTable() 18 self.cross_correlation_map = None 19 self.drift_xy = None 20 self.drift_x = None 21 self.drift_y = None 22 23 # @timeit 24 def estimate(self, image_array, **kwargs): 25 self.set_estimator_params(**kwargs) 26 27 n_slices = image_array.shape[0] 28 29 # x0, y0, x1, y1 correspond to the exact coordinates of the roi to be used or full image dims and should be a tuple 30 if self.estimator_table.params["use_roi"] and self.estimator_table.params["roi"] is not None: # crops image to roi 31 print(self.estimator_table.params["use_roi"], self.estimator_table.params["roi"]) 32 x0, y0, x1, y1 = tuple(self.estimator_table.params["roi"]) 33 image_arr = image_array[:, y0:y1+1, x0:x1+1] 34 else: 35 image_arr = image_array 36 37 # checks time averaging, in case it's lower than 1 defaults to 1 38 # if higher than n_slices/2 defaults to n_slices/2 39 if self.estimator_table.params["time_averaging"] < 1: 40 self.estimator_table.params["time_averaging"] = 1 41 elif self.estimator_table.params["time_averaging"] > int(n_slices/2): 42 self.estimator_table.params["time_averaging"] = int(n_slices/2) 43 44 # case of no temporal averaging 45 if self.estimator_table.params["time_averaging"] == 1: 46 image_averages = image_arr 47 else: # case of temporal averaging 48 # calculates number of time blocks for averaging 49 image_averages = self.compute_temporal_averaging(image_arr) 50 51 method = self.estimator_table.params["shift_calc_method"] 52 53 if method == "rcc": 54 shifts = rcc(image_averages, max_shift=self.estimator_table.params["max_expected_drift"]) 55 self.drift_x = shifts[0] 56 self.drift_y = shifts[1] 57 else: 58 self.cross_correlation_map = np.array(calculate_ccm(np.array(image_averages).astype(np.float32), self.estimator_table.params["ref_option"])) 59 max_shift = self.estimator_table.params["max_expected_drift"] 60 if max_shift > 0 and max_shift*2+1 < self.cross_correlation_map.shape[1] and max_shift*2+1 < self.cross_correlation_map.shape[2]: 61 ccm_x_start = int(self.cross_correlation_map.shape[1]/2 - max_shift) 62 ccm_y_start = int(self.cross_correlation_map.shape[0]/2 - max_shift) 63 slice_ccm = self.cross_correlation_map[ccm_y_start:ccm_y_start+(max_shift*2), ccm_x_start:ccm_x_start+(max_shift*2)] 64 self.get_shifts_from_ccm() 65 66 if self.estimator_table.params["time_averaging"] > 1: 67 68 print("Interpolating time points") 69 x_idx = np.linspace(1, image_array.shape[0], num=self.drift_x.shape[0], endpoint=True, dtype=int) 70 x_interpolator = interp1d(x_idx, self.drift_x, kind="cubic") # linear seems to work similar as in nanoj-core however its codebase calls setInterpolation("Bicubic") 71 self.drift_x = x_interpolator(range(1, image_array.shape[0] + 1)) 72 y_idx = np.linspace(1, image_array.shape[0], num=self.drift_y.shape[0], endpoint=True, dtype=int) 73 y_interpolator = interp1d(y_idx, self.drift_y, kind="cubic") # linear seems to work similar as in nanoj-core however its codebase calls setInterpolation("Bicubic") 74 self.drift_y = y_interpolator(range(1, image_array.shape[0] + 1)) 75 76 self.drift_xy = [] 77 for i in range(image_array.shape[0]): 78 self.drift_xy.append(sqrt(pow(self.drift_x[i], 2) + pow(self.drift_y[i], 2))) 79 self.drift_xy = np.array(self.drift_xy) 80 81 self.create_drift_table() 82 83 if self.estimator_table.params["apply"]: 84 drift_corrector = DriftCorrector() 85 drift_corrector.estimator_table = self.estimator_table 86 tmp = drift_corrector.apply_correction(image_array) 87 return tmp 88 else: 89 return None 90 91 def compute_temporal_averaging(self, image_arr): 92 n_slices = image_arr.shape[0] 93 94 if self.estimator_table.params["use_roi"]: 95 x0, y0, x1, y1 = self.estimator_table.params["roi"] 96 else: 97 x0, y0, x1, y1 = 0, 0, image_arr.shape[2]-1, image_arr.shape[1]-1 98 99 n_blocks = int(n_slices / self.estimator_table.params["time_averaging"]) 100 if (n_slices % self.estimator_table.params["time_averaging"]) != 0: 101 n_blocks += 1 102 image_averages = np.zeros((n_blocks, y1+1-y0, x1+1-x0)) 103 for i in range(n_blocks): 104 t_start = i * self.estimator_table.params["time_averaging"] 105 t_stop = (i + 1) * self.estimator_table.params["time_averaging"] 106 image_averages[i] = np.mean(image_arr[t_start:t_stop, :, :], axis=0) 107 return image_averages 108 109 def get_shift_from_ccm_slice(self, slice_index): 110 slice_ccm = self.cross_correlation_map[slice_index] 111 112 w = slice_ccm.shape[1] 113 h = slice_ccm.shape[0] 114 115 radius_x = w / 2.0 116 radius_y = h / 2.0 117 118 method = self.estimator_table.params["shift_calc_method"] 119 120 if method == "Max Fitting": 121 optimizer = GetMaxOptimizer(slice_ccm) 122 shift_y, shift_x = optimizer.get_max() 123 elif method == "Max": 124 shift_y, shift_x = np.unravel_index(slice_ccm.argmax(), slice_ccm.shape) 125 126 shift_x = round(radius_x - shift_x - 0.5, 3) 127 shift_y = round(radius_y - shift_y - 0.5, 3) 128 129 return (shift_x, shift_y) 130 131 def get_shifts_from_ccm(self): 132 133 drift_x = [] 134 drift_y = [] 135 drift = [] 136 137 for i in range(self.cross_correlation_map.shape[0]): 138 drift.append(self.get_shift_from_ccm_slice(i)) 139 140 drift = np.array(drift) 141 drift_x = drift[:, 0] 142 drift_y = drift[:, 1] 143 144 bias_x = drift_x[0] 145 bias_y = drift_y[0] 146 147 self.drift_x = np.zeros((drift_x.shape[0])) 148 self.drift_y = np.zeros((drift_y.shape[0])) 149 150 for i in range(0, self.cross_correlation_map.shape[0]): 151 self.drift_x[i] = drift_x[i] - bias_x 152 self.drift_y[i] = drift_y[i] - bias_y 153 if self.estimator_table.params["ref_option"] == 1 and i > 0: 154 self.drift_x[i] += self.drift_x[i-1] 155 self.drift_y[i] += self.drift_y[i-1] 156 157 self.drift_x = np.array(self.drift_x) 158 self.drift_y = np.array(self.drift_y) 159 160 def create_drift_table(self): 161 table = [] 162 for i in range(0, self.drift_xy.shape[0]): 163 table.append([self.drift_xy[i], self.drift_x[i], self.drift_y[i]]) 164 table = np.array(table) 165 self.estimator_table.drift_table = table 166 167 def save_drift_table(self, save_as_npy=True, path=None): 168 if save_as_npy: 169 self.estimator_table.export_npy(path=path) 170 else: 171 self.estimator_table.export_csv(path=path) 172 173 def set_estimator_params(self, **kwargs): 174 self.estimator_table.set_params(**kwargs)
def
estimate(self, image_array, **kwargs):
24 def estimate(self, image_array, **kwargs): 25 self.set_estimator_params(**kwargs) 26 27 n_slices = image_array.shape[0] 28 29 # x0, y0, x1, y1 correspond to the exact coordinates of the roi to be used or full image dims and should be a tuple 30 if self.estimator_table.params["use_roi"] and self.estimator_table.params["roi"] is not None: # crops image to roi 31 print(self.estimator_table.params["use_roi"], self.estimator_table.params["roi"]) 32 x0, y0, x1, y1 = tuple(self.estimator_table.params["roi"]) 33 image_arr = image_array[:, y0:y1+1, x0:x1+1] 34 else: 35 image_arr = image_array 36 37 # checks time averaging, in case it's lower than 1 defaults to 1 38 # if higher than n_slices/2 defaults to n_slices/2 39 if self.estimator_table.params["time_averaging"] < 1: 40 self.estimator_table.params["time_averaging"] = 1 41 elif self.estimator_table.params["time_averaging"] > int(n_slices/2): 42 self.estimator_table.params["time_averaging"] = int(n_slices/2) 43 44 # case of no temporal averaging 45 if self.estimator_table.params["time_averaging"] == 1: 46 image_averages = image_arr 47 else: # case of temporal averaging 48 # calculates number of time blocks for averaging 49 image_averages = self.compute_temporal_averaging(image_arr) 50 51 method = self.estimator_table.params["shift_calc_method"] 52 53 if method == "rcc": 54 shifts = rcc(image_averages, max_shift=self.estimator_table.params["max_expected_drift"]) 55 self.drift_x = shifts[0] 56 self.drift_y = shifts[1] 57 else: 58 self.cross_correlation_map = np.array(calculate_ccm(np.array(image_averages).astype(np.float32), self.estimator_table.params["ref_option"])) 59 max_shift = self.estimator_table.params["max_expected_drift"] 60 if max_shift > 0 and max_shift*2+1 < self.cross_correlation_map.shape[1] and max_shift*2+1 < self.cross_correlation_map.shape[2]: 61 ccm_x_start = int(self.cross_correlation_map.shape[1]/2 - max_shift) 62 ccm_y_start = int(self.cross_correlation_map.shape[0]/2 - max_shift) 63 slice_ccm = self.cross_correlation_map[ccm_y_start:ccm_y_start+(max_shift*2), ccm_x_start:ccm_x_start+(max_shift*2)] 64 self.get_shifts_from_ccm() 65 66 if self.estimator_table.params["time_averaging"] > 1: 67 68 print("Interpolating time points") 69 x_idx = np.linspace(1, image_array.shape[0], num=self.drift_x.shape[0], endpoint=True, dtype=int) 70 x_interpolator = interp1d(x_idx, self.drift_x, kind="cubic") # linear seems to work similar as in nanoj-core however its codebase calls setInterpolation("Bicubic") 71 self.drift_x = x_interpolator(range(1, image_array.shape[0] + 1)) 72 y_idx = np.linspace(1, image_array.shape[0], num=self.drift_y.shape[0], endpoint=True, dtype=int) 73 y_interpolator = interp1d(y_idx, self.drift_y, kind="cubic") # linear seems to work similar as in nanoj-core however its codebase calls setInterpolation("Bicubic") 74 self.drift_y = y_interpolator(range(1, image_array.shape[0] + 1)) 75 76 self.drift_xy = [] 77 for i in range(image_array.shape[0]): 78 self.drift_xy.append(sqrt(pow(self.drift_x[i], 2) + pow(self.drift_y[i], 2))) 79 self.drift_xy = np.array(self.drift_xy) 80 81 self.create_drift_table() 82 83 if self.estimator_table.params["apply"]: 84 drift_corrector = DriftCorrector() 85 drift_corrector.estimator_table = self.estimator_table 86 tmp = drift_corrector.apply_correction(image_array) 87 return tmp 88 else: 89 return None
def
compute_temporal_averaging(self, image_arr):
91 def compute_temporal_averaging(self, image_arr): 92 n_slices = image_arr.shape[0] 93 94 if self.estimator_table.params["use_roi"]: 95 x0, y0, x1, y1 = self.estimator_table.params["roi"] 96 else: 97 x0, y0, x1, y1 = 0, 0, image_arr.shape[2]-1, image_arr.shape[1]-1 98 99 n_blocks = int(n_slices / self.estimator_table.params["time_averaging"]) 100 if (n_slices % self.estimator_table.params["time_averaging"]) != 0: 101 n_blocks += 1 102 image_averages = np.zeros((n_blocks, y1+1-y0, x1+1-x0)) 103 for i in range(n_blocks): 104 t_start = i * self.estimator_table.params["time_averaging"] 105 t_stop = (i + 1) * self.estimator_table.params["time_averaging"] 106 image_averages[i] = np.mean(image_arr[t_start:t_stop, :, :], axis=0) 107 return image_averages
def
get_shift_from_ccm_slice(self, slice_index):
109 def get_shift_from_ccm_slice(self, slice_index): 110 slice_ccm = self.cross_correlation_map[slice_index] 111 112 w = slice_ccm.shape[1] 113 h = slice_ccm.shape[0] 114 115 radius_x = w / 2.0 116 radius_y = h / 2.0 117 118 method = self.estimator_table.params["shift_calc_method"] 119 120 if method == "Max Fitting": 121 optimizer = GetMaxOptimizer(slice_ccm) 122 shift_y, shift_x = optimizer.get_max() 123 elif method == "Max": 124 shift_y, shift_x = np.unravel_index(slice_ccm.argmax(), slice_ccm.shape) 125 126 shift_x = round(radius_x - shift_x - 0.5, 3) 127 shift_y = round(radius_y - shift_y - 0.5, 3) 128 129 return (shift_x, shift_y)
def
get_shifts_from_ccm(self):
131 def get_shifts_from_ccm(self): 132 133 drift_x = [] 134 drift_y = [] 135 drift = [] 136 137 for i in range(self.cross_correlation_map.shape[0]): 138 drift.append(self.get_shift_from_ccm_slice(i)) 139 140 drift = np.array(drift) 141 drift_x = drift[:, 0] 142 drift_y = drift[:, 1] 143 144 bias_x = drift_x[0] 145 bias_y = drift_y[0] 146 147 self.drift_x = np.zeros((drift_x.shape[0])) 148 self.drift_y = np.zeros((drift_y.shape[0])) 149 150 for i in range(0, self.cross_correlation_map.shape[0]): 151 self.drift_x[i] = drift_x[i] - bias_x 152 self.drift_y[i] = drift_y[i] - bias_y 153 if self.estimator_table.params["ref_option"] == 1 and i > 0: 154 self.drift_x[i] += self.drift_x[i-1] 155 self.drift_y[i] += self.drift_y[i-1] 156 157 self.drift_x = np.array(self.drift_x) 158 self.drift_y = np.array(self.drift_y)